//
//  DGCoreTextEditor.m
//  DGCoreTextView
//
//  Created by Jinxiao on 13-1-11.
//  Copyright (c) 2013年 debugeek. All rights reserved.
//

#import "DGCoreTextEditor.h"
#import "DGCoreTextPattern.h"
#import "DGCoreTextPatternSetting.h"

@interface DGCoreTextEditor ()
@property (readwrite, nonatomic, strong) NSString *originalString;
@end

@implementation DGCoreTextEditor

- (id)initWithString:(NSString *)string
{
    self = [super init];
    if(self)
    {
        self.originalString = string;
        self.patterns = [[NSMutableArray alloc] init];
        self.styledString = [[NSMutableAttributedString alloc] initWithString:string];
    }
    
    return self;
}

- (void)process
{
    [self.styledString setParagraphWithLineBreakMode:kCTLineBreakByCharWrapping textAlignment:kCTTextAlignmentLeft lineSpacingMin:5.f lineSpacingMax:10.f lineHeightMax:20.f];
    [self.styledString setTextColor:self.defaultColor];
    [self.styledString setTextFont:self.defaultFont];
    
    NSArray *sortedPatterns = [self.patterns sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        DGCoreTextPattern *pattern1 = (DGCoreTextPattern *)obj1;
        DGCoreTextPattern *pattern2 = (DGCoreTextPattern *)obj2;
        
        if(pattern1.range.location < pattern2.range.location)
        {
            return NSOrderedAscending;
        }
        else if(pattern1.range.location == pattern2.range.location)
        {
            return NSOrderedSame;
        }
        else
        {
            return NSOrderedDescending;
        }
    }];
    [self.patterns removeAllObjects];
    [self.patterns addObjectsFromArray:sortedPatterns];
    
    __block NSRange nextRange = NSMakeRange(0, 0);
    NSMutableString *textString = [self.originalString mutableCopy];
    [self.patterns enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        DGCoreTextPattern *pattern = (DGCoreTextPattern *)obj;
        
        NSString *subString = [textString substringFromIndex:nextRange.location];
        NSRange nameRange = [subString rangeOfString:pattern.text];
        
        if(nameRange.location != NSNotFound)
        {
            NSRange newNameRange = nameRange;
            newNameRange.location += nextRange.location;
            
            [self.styledString setTextColor:pattern.patternSetting.defaultColor range:newNameRange];
            [self.styledString setTextFont:pattern.patternSetting.defaultFont range:newNameRange];
            
            pattern.range = newNameRange;
            
            NSDictionary *attribute = @{@"pattern" : pattern};
            [self.styledString setPattern:attribute range:newNameRange];
            
            nextRange.location = newNameRange.location + nameRange.length;
        }
    }];
}

- (void)preprocessWithPatternSetting:(DGCoreTextPatternSetting *)patternSetting
{
    if(self.originalString.length == 0) {
        return;
    }
    
    NSArray *patterns = [patternSetting preprocessedPatternsForString:self.originalString];
    [self.patterns addObjectsFromArray:patterns];
}

- (UIFont *)defaultFont
{
    if(!_defaultFont)
    {
        _defaultFont = [UIFont systemFontOfSize:16.f];
    }
    return _defaultFont;
}

- (UIColor *)defaultColor
{
    if(!_defaultColor)
    {
        _defaultColor = [UIColor blackColor];
    }
    return _defaultColor;
}

- (CGSize)sizeThatFits:(CGSize)constrainedSize {
    CGSize fitSize = CGSizeZero;

    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.styledString);
    CGRect drawingRect = CGRectMake(0, 0, constrainedSize.width, constrainedSize.height);
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, drawingRect);
    CTFrameRef drawingFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
    CGPathRelease(path);
    CFRelease(framesetter);

    NSArray *lines = (NSArray *)CTFrameGetLines(drawingFrame);
    CGPoint origins[[lines count]];
    CTFrameGetLineOrigins(drawingFrame, CFRangeMake(0, 0), origins);

    CGFloat lineOffsetY = origins[[lines count] - 1].y;

    CGFloat ascent;
    CGFloat descent;
    CGFloat leading;

    if([lines count] > 0)
    {
        CTLineRef line = (__bridge CTLineRef)[lines objectAtIndex:[lines count] - 1];
        CTLineGetTypographicBounds(line, &ascent, &descent, &leading);

        fitSize.width = constrainedSize.width;
        fitSize.height = constrainedSize.height - lineOffsetY + descent + 1.0;
    }

    CFRelease(drawingFrame);

    return fitSize;
}

@end
